////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __WN_CRITICAL_SECTION_H__
#define __WN_CRITICAL_SECTION_H__

#include "WNCore/inc/WNBase.h"

#ifdef _WN_WINDOWS
    #include <windows.h>

    typedef CRITICAL_SECTION WN_CRITICAL_SECTION_T;
#elif defined _WN_LINUX
    #include "WNConcurrency/inc/WNThread.h"
    #include "WNConcurrency/inc/WNSemaphore.h"

    typedef struct {
        WN_ATOM_T mCounter;
        WN_THREAD_ID_T mOwner;
        WN_UINT32 mRecursion;
        WN_SEMAPHORE_T mSemaphore;
    } WN_CRITICAL_SECTION_T;
#endif

__WN_INLINE WN_VOID WNCriticalSectionInitialize(WN_CRITICAL_SECTION_T* _criticalSection);
__WN_INLINE WN_VOID WNCriticalSectionDestroy(WN_CRITICAL_SECTION_T* _criticalSection);
__WN_INLINE WN_BOOL WNCriticalSectionTryEnter(WN_CRITICAL_SECTION_T* _criticalSection);
__WN_INLINE WN_VOID WNCriticalSectionEnter(WN_CRITICAL_SECTION_T* _criticalSection);
__WN_INLINE WN_VOID WNCriticalSectionLeave(WN_CRITICAL_SECTION_T* _criticalSection);

#ifdef _WN_CPLUSPLUS
    class WNCriticalSectionScopeLock;

    class WNCriticalSection {
    public:
        __WN_INLINE WNCriticalSection();
        __WN_INLINE ~WNCriticalSection();

        __WN_INLINE WN_VOID Enter();
        __WN_INLINE WN_BOOL TryEnter();
        __WN_INLINE WN_VOID Leave();

    private:
        friend class WNCriticalSectionScopeLock;

    private:
        WN_CRITICAL_SECTION_T mCriticalSection;
    };

    class WNCriticalSectionScopeLock {
    public:
        __WN_INLINE WNCriticalSectionScopeLock(WN_CRITICAL_SECTION_T* _criticalSection);
        __WN_INLINE WNCriticalSectionScopeLock(WNCriticalSection& _criticalSection);
        __WN_INLINE ~WNCriticalSectionScopeLock();

    private:
        WNCriticalSectionScopeLock() {}

    private:
        WN_CRITICAL_SECTION_T* mCriticalSection;
    };

    #define WN_CRITICAL_SECTION_SCOPE_LOCK(_criticalSection) WNCriticalSectionScopeLock lock__COUNTER____LINE__(_criticalSection)
#endif

#include "WNConcurrency/inc/WNCriticalSection.inl"

#endif // __WN_CRITICAL_SECTION_H__